﻿// -----------------------------------------------------------------------
// <copyright file="DirectoryHandler.cs" company="Microsoft">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------
namespace WebServer.BusinessLogic.Handlers
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Text.RegularExpressions;
    using WebServer.BusinessLogic.Handlers.Interface;

    /// <summary>
    /// Handles directory requests.
    /// </summary>
    public class DirectoryHandler : Handler
    {
        /// <summary>
        /// interface for testing
        /// </summary>
        private IFileSystemProvider fileSystemProvider;

        private static string dirStyle;

        /// <summary>
        /// Initializes a new instance of the <see cref="DirectoryHandler" /> class using IFileSystemProvider interface
        /// </summary>
        /// <param name="fs">fake interface for testing</param>
        public DirectoryHandler(IFileSystemProvider fs)
        {
            this.fileSystemProvider = fs;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="DirectoryHandler" /> class
        /// </summary>
        public DirectoryHandler()
        {
            this.fileSystemProvider = new FileSystemProvider();
        }

        static DirectoryHandler()
        {
            dirStyle = File.ReadAllText(Configurator.Instance.ResourceFolder + "\\styles\\style.css");
        }

        /// <summary>
        /// Tries to handle request.
        /// </summary>
        /// <param name="request">
        /// The request.
        /// </param>
        /// <returns>
        /// The WebServer.BusinessLogic.Response.
        /// </returns>
        public override Response Handle(Request request)
        {
            if (request.HttpPath.EndsWith("/") || !Regex.IsMatch(request.HttpPath, @"\..*$"))
            {
                string path = Configurator.Instance.RelativeWwwPath + request.HttpPath.Replace("/", "\\");
                if (!this.fileSystemProvider.DirectoryExists(path))
                {
                    return NextHandler.Handle(request);
                }

                const string SIndexHtml = "index.html";
                if (this.fileSystemProvider.FileExists(path.TrimEnd(new[] { '\\' }) + "\\" + SIndexHtml))
                {
                    request.HttpPath = request.HttpPath.TrimEnd(new[] { '/' }) + "/" + SIndexHtml;
                    return NextHandler.Handle(request);
                }

                // get all files and folders
                var descendants = new List<FileSystemInfoModel>(this.fileSystemProvider.GetFileSystemInfos(path));
                
                // create content of resulting webpage
                string webPage = this.CreateWebPage(descendants.ToList(), request);

                // create reponse for webpage
                Response toReturn = new Response("text/html", request.HttpVersion, Encoding.UTF8.GetBytes(webPage));
                if (Configurator.Instance.UseResponseCompression && request.AcceptEncoding == EnumAcceptEncoding.Gzip)
                {
                    toReturn.Data = Handler.GzipCompress(toReturn.Data);
                    toReturn.ContentEncoding = "gzip";
                }

                return toReturn;
            }

            return NextHandler.Handle(request);
        }

        /// <summary>
        /// Creates web-page showing file structure.
        /// </summary>
        /// <param name="elements">
        /// The elements.
        /// </param>
        /// <param name="request">
        /// The request.
        /// </param>
        /// <returns>
        /// The System.String.
        /// </returns>
        public string CreateWebPage(IEnumerable<FileSystemInfoModel> elements, Request request)
        {
            StringBuilder webPage = new StringBuilder();
            webPage.Append("<html>\n<head>\n");
            webPage.Append("<style type=\"text/css\">\n");
            webPage.Append(dirStyle);
            webPage.Append("</style>");
            webPage.Append("<link rel=\"stylesheet\" href=\"style.css\" type=\"text/css\"/>");
            webPage.Append("<title>Directory</title>\n</head>\n");
            webPage.Append(string.Format("<body>\n<h1>Directory</h1>\n<h2>{0}</h2>\n", request.HttpPath));
            webPage.Append("<table>\n<tr><th>Name</th><th>Type</th>\n</tr>");

            // add "Go Back" link
            string path = request.HttpPath.Trim(new[] { '/' });
            int idx = path.IndexOf('/');
            if (idx >= 0)
            {
                path = path.Substring(idx + 1).TrimEnd(new[] { '/' }) + "/";
            }
            else
            {
                path = string.Empty;
            }

            const string dirFormat = "<tr><td><a href=\"{0}\">{1}</a></td><td>{2}</td></tr>";

            webPage.Append(string.Format(dirFormat, path + "..", "..", String.Empty));
            
            foreach (FileSystemInfoModel element in elements)
            {
                string link = element.FullName.Remove(0, Configurator.Instance.RelativeWwwPath.Length).Replace('\\', '/');
                string extension = element.Extension.Length != 0 ? element.Extension : "Directory";
                webPage.Append(string.Format(dirFormat, link, element.Name, extension));
            }

            webPage.Append("</table>\n</body>\n</html>");
            return webPage.ToString();
        }
    }
}
